/**
 * Copyright (C) 2013-2014 the original author or authors.
 */
package com.foreveross.bsl.push;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.Validate;
import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.foreveross.bsl.JsonMapper;

/**
 * xxx
 *
 * @author Wangyi
 * @version v1.0
 *
 * @date 2013-12-5
 *
 */
public class PushClient {
	
	private static final Logger log = LoggerFactory.getLogger(PushClient.class);
	private static final String URL_CHECKIN="checkinservice/checkins";
	private static final String URL_RECEIPT="receipts";
	private static final String URL_PUSH="push/notifications";
	private final String pushUrl;
	private String deviceId, appId;
	private String osName="push-test", osVersion="0.1", deviceName="newuser";
	private String sessionKey;
	
	public PushClient(String url){
		if(!url.endsWith("/")){
			this.pushUrl=url+"/";
		}
		else{
			this.pushUrl=url;
		}
	}
	
	public void setSessionKey(String sessionKey){
		this.sessionKey=sessionKey;
	}
	
	protected String getToken(){
		return "unknown";
	}
	
	private DeviceCheckin buildDeviceCheckin(String token){
		DeviceCheckin dc=new DeviceCheckin();
		dc.setDeviceId(deviceId);
		dc.setAppId(appId);
		dc.setPushToken(token);
		dc.setChannelId("openfire");
		dc.setDeviceName(deviceName);
		dc.setOsName(osName);
		dc.setOsVersion(osVersion);
		dc.setTags(new TagEntry[]{new TagEntry("platform", "push-test")});
		return dc;
	}

	public void checkin() throws ClientProtocolException, IOException{
		String token=this.getToken();
		DefaultHttpClient httpclient = new DefaultHttpClient();
		try {
			HttpPut request = new HttpPut(pushUrl+URL_CHECKIN);
			StringEntity payload=new StringEntity(JsonMapper.NON_EMPTY_JSON_MAPPER.toJson(this.buildDeviceCheckin(token)));
			request.addHeader("Content-Type", "application/json; charset=utf-8");
			if(sessionKey!=null){
				request.addHeader("sessionKey", sessionKey);
			}
			request.setEntity(payload);
			log.debug("开始签到...");
			HttpResponse response = httpclient.execute(request);
			HttpEntity entity = response.getEntity();
			log.debug("response status line: {}", response.getStatusLine());
			if(response.getEntity()!=null){
				if(log.isDebugEnabled()){
					log.debug("response content: {}", IOUtils.toString(response.getEntity().getContent()));
				}
			}
			EntityUtils.consume(entity);
		} finally {
			httpclient.getConnectionManager().shutdown();
		}
	}
	
	public boolean receipt(String msgId) throws ClientProtocolException, IOException{
		boolean result=true;
		DefaultHttpClient httpclient = new DefaultHttpClient();
		try {
			HttpPut request = new HttpPut(pushUrl+URL_RECEIPT);
			List <NameValuePair> nvps = new ArrayList <NameValuePair>();
			nvps.add(new BasicNameValuePair("deviceId", deviceId));
			nvps.add(new BasicNameValuePair("msgId", msgId));
            nvps.add(new BasicNameValuePair("appId", appId));
            
            if(sessionKey!=null){
				request.addHeader("sessionKey", sessionKey);
			}
            request.setEntity(new UrlEncodedFormEntity(nvps, Consts.UTF_8));
            log.debug("发送回执...");
			HttpResponse response = httpclient.execute(request);
			HttpEntity entity = response.getEntity();
			int status=response.getStatusLine().getStatusCode();
			if(status<200 || status>299){
				result=false;
			}
			log.debug("response status line: {}", response.getStatusLine());
			if(response.getEntity()!=null){
				if(log.isDebugEnabled()){
					log.debug("response content: {}", IOUtils.toString(response.getEntity().getContent()));
				}
			}
			EntityUtils.consume(entity);
		} finally {
			httpclient.getConnectionManager().shutdown();
		}
		return result;
	}
	
	public void push(MessageParams msgParams) throws Exception{
		push(msgParams, 1);
	}
	
	public void push(MessageParams msgParams, int repeat) throws Exception {
		push(msgParams, repeat, false);
	}
	
	public void push(MessageParams msgParams, int repeat, boolean abortOnError) throws Exception {
		DefaultHttpClient httpclient = new DefaultHttpClient();
		try {
			String msg=msgParams.getMessage().getTitle();
			for(int i=1; i<=repeat; i++){
				msgParams.getMessage().setTitle(wrapMsg(msg, i));
				log.debug("开始提交推送请求...{}", i);
				try {
					doPush(msgParams, httpclient);
				} catch (Exception e) {
					if(!abortOnError){
						log.error(i+" push request error!", e);
					}
					else{
						throw e;
					}
				}
			}
		} finally {
			httpclient.getConnectionManager().shutdown();
		}
	}
	
	private String wrapMsg(String msg, int index){
		StringBuilder sb=new StringBuilder();
		sb.append(System.currentTimeMillis()).append("@").append(msg).append(" ").append(index);
		return sb.toString();
	}

	private void doPush(MessageParams msgParams, DefaultHttpClient httpclient) throws UnsupportedEncodingException,
			IOException, ClientProtocolException {
		HttpPost request = new HttpPost(pushUrl+URL_PUSH);
		String json=JsonMapper.NON_EMPTY_JSON_MAPPER.toJson(msgParams);
		log.trace("payload: {}", json);
		StringEntity payload=new StringEntity(json);
		request.addHeader("Content-Type", "application/json; charset=utf-8");
		request.addHeader("sessionKey", sessionKey);
		request.setEntity(payload);
		HttpResponse response = httpclient.execute(request);
		HttpEntity entity = response.getEntity();
		log.debug("response status line: {}", response.getStatusLine());
		if(response.getEntity()!=null){
			if(log.isDebugEnabled()){
				log.debug("response content: {}", IOUtils.toString(response.getEntity().getContent()));
			}
		}
		EntityUtils.consume(entity);
	}
	
	/**
	 * @return the osName
	 */
	public String getOsName() {
		return osName;
	}

	/**
	 * @param osName the osName to set
	 */
	public void setOsName(String osName) {
		this.osName = osName;
	}

	/**
	 * @return the osVersion
	 */
	public String getOsVersion() {
		return osVersion;
	}

	/**
	 * @param osVersion the osVersion to set
	 */
	public void setOsVersion(String osVersion) {
		this.osVersion = osVersion;
	}

	/**
	 * @return the deviceName
	 */
	public String getDeviceName() {
		return deviceName;
	}

	/**
	 * @param deviceName the deviceName to set
	 */
	public void setDeviceName(String deviceName) {
		this.deviceName = deviceName;
	}

	/**
	 * @return the pushUrl
	 */
	public String getPushUrl() {
		return pushUrl;
	}

	/**
	 * @return the deviceId
	 */
	public String getDeviceId() {
		return deviceId;
	}

	/**
	 * @return the appId
	 */
	public String getAppId() {
		return appId;
	}

	/**
	 * @return the sessionKey
	 */
	public String getSessionKey() {
		return sessionKey;
	}

	/**
	 * @param deviceId the deviceId to set
	 */
	public void setDeviceId(String deviceId) {
		this.deviceId = deviceId;
	}

	/**
	 * @param appId the appId to set
	 */
	public void setAppId(String appId) {
		this.appId = appId;
	}
}
